import { buildAsyncRoutes, constantRoutes } from '@/router/modules_rest'
import Layout from '@/layout/index'
import EmptyLayout from '@/layout/empty'

/**
 * Use meta.role to determine if the current user has permission
 * @param roles
 * @param route
 */
function hasPermission(roles, route) {
  if (route.meta && route.meta.roles) {
    return roles.some((role) => route.meta.roles.includes(role))
  }
  return true
}

function buildRouteTableByMenus(menus) {
  const routes = []

  const loadView = (view) => (resolve) => require([`@/views/rest${view}`], resolve)

  function leafMenu(menu, props = {}) {
    const { id, name, resource, component, icon, componentName } = menu
    return {
      path: component,
      name: componentName || name,
      component: props.component ? loadView(props.component) : (props.top ? Layout : EmptyLayout),
      hidden: menu.visibleStatus !== 1,
      meta: {
        id,
        title: name,
        icon: icon,
        resource
      }
    }
  }

  function recursiveMenu(menu, props = {}) {
    const children = menu.subList || []
    const leaf = children.length === 0

    if (!menu.visibleStatus && !menu.component) {
      // 不需要渲染
      return null
    }

    if (leaf && !props.top) {
      // 非顶层的叶子节点, 直接展现页面组件
      return leafMenu(menu, { component: menu.component, top: false })
    }

    const item = leafMenu(menu, props)

    if (!leaf) {
      item.children = []
      menu.subList.forEach((sub) => {
        const route = recursiveMenu(sub, { component: sub.component, top: false })
        if (route) {
          item.children.push(route)
        }
      })
    } else if (props.top && menu.component) {
      // 如果是顶层叶子节点, 为了套在 Layout 下面需要再包一个子节点展示实际的逻辑页面
      item.children = [leafMenu(menu, { component: menu.component, top: false })]
    }

    return item
  }

  menus.forEach((menu) => {
    // 目前只给顶级链接显示图标, 以后可以允许配置图标
    const route = recursiveMenu(menu, {
      icon: 'component',
      top: true
    })
    if (route) {
      routes.push(route)
    }
  })

  return routes
}

/**
 * Filter asynchronous routing tables by recursion
 * @param routes asyncRoutes
 * @param roles
 */
export function filterAsyncRoutes(routes, roles) {
  const res = []

  routes.forEach((route) => {
    const tmp = { ...route }
    if (hasPermission(roles, tmp)) {
      if (tmp.children) {
        tmp.children = filterAsyncRoutes(tmp.children, roles)
      }
      res.push(tmp)
    }
  })

  return res
}

const STATE = {
  routes: [],
  addRoutes: []
}

const mutations = {
  SET_ROUTES: (state, routes) => {
    state.addRoutes = routes
    state.routes = constantRoutes.concat(routes)
  }
}

const actions = {
  generateRoutes({ commit, rootGetters }, roles) {
    return new Promise((resolve) => {
      const asyncRoutes = buildAsyncRoutes(buildRouteTableByMenus(rootGetters.menus))
      const accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)
      commit('SET_ROUTES', accessedRoutes)
      resolve(accessedRoutes)
    })
  }
}

export default {
  namespaced: true,
  state: STATE,
  mutations,
  actions
}
